package cn.iocoder.yudao.module.system.service.user;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.exception.ServiceException;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils;
import cn.iocoder.yudao.framework.datapermission.core.util.DataPermissionUtils;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.MPJLambdaWrapperX;
import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils;
import cn.iocoder.yudao.module.infra.api.config.ConfigApi;
import cn.iocoder.yudao.module.infra.api.file.FileApi;
import cn.iocoder.yudao.module.system.controller.admin.auth.vo.AuthRegisterReqVO;
import cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept.DeptRespVO;
import cn.iocoder.yudao.module.system.controller.admin.user.vo.profile.UserProfileUpdatePasswordReqVO;
import cn.iocoder.yudao.module.system.controller.admin.user.vo.profile.UserProfileUpdateReqVO;
import cn.iocoder.yudao.module.system.controller.admin.user.vo.user.*;
import cn.iocoder.yudao.module.system.convert.user.UserConvert;
import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO;
import cn.iocoder.yudao.module.system.dal.dataobject.dept.UserPostDO;
import cn.iocoder.yudao.module.system.dal.dataobject.tenant.TenantDO;
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
import cn.iocoder.yudao.module.system.dal.dataobject.user.UserDeptDO;
import cn.iocoder.yudao.module.system.dal.dataobject.user.UserTenantDO;
import cn.iocoder.yudao.module.system.dal.mysql.dept.DeptMapper;
import cn.iocoder.yudao.module.system.dal.mysql.dept.UserPostMapper;
import cn.iocoder.yudao.module.system.dal.mysql.tenant.TenantMapper;
import cn.iocoder.yudao.module.system.dal.mysql.user.AdminUserMapper;
import cn.iocoder.yudao.module.system.dal.mysql.user.UserDeptMapper;
import cn.iocoder.yudao.module.system.dal.mysql.user.UserTenantMapper;
import cn.iocoder.yudao.module.system.service.dept.DeptService;
import cn.iocoder.yudao.module.system.service.dept.PostService;
import cn.iocoder.yudao.module.system.service.permission.PermissionService;
import cn.iocoder.yudao.module.system.service.tenant.TenantService;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.google.common.annotations.VisibleForTesting;
import com.mzt.logapi.context.LogRecordContext;
import com.mzt.logapi.service.impl.DiffParseFunction;
import com.mzt.logapi.starter.annotation.LogRecord;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Lazy;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.validation.ConstraintViolationException;
import java.io.InputStream;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
import static cn.iocoder.yudao.module.system.enums.LogRecordConstants.*;

/**
 * 后台用户 Service 实现类
 *
 * @author 芋道源码
 */
@Service("adminUserService")
@Slf4j
public class AdminUserServiceImpl implements AdminUserService {

    static final String USER_INIT_PASSWORD_KEY = "system.user.init-password";

    @Resource
    private AdminUserMapper userMapper;

    @Resource
    private DeptService deptService;
    @Resource
    private DeptMapper deptMapper;
    @Resource
    private PostService postService;
    @Resource
    private PermissionService permissionService;
    @Resource
    private PasswordEncoder passwordEncoder;
    @Resource
    @Lazy // 延迟，避免循环依赖报错
    private TenantService tenantService;
    @Resource
    private TenantMapper tenantMapper;

    @Resource
    private UserPostMapper userPostMapper;
    @Resource
    private UserDeptMapper userDeptMapper;

    @Resource
    private UserTenantMapper userTenantMapper;

    @Resource
    private FileApi fileApi;
    @Resource
    private ConfigApi configApi;


    @Override
    @Transactional(rollbackFor = Exception.class)
    @LogRecord(type = SYSTEM_USER_TYPE, subType = SYSTEM_USER_CREATE_SUB_TYPE, bizNo = "{{#user.id}}",
            success = SYSTEM_USER_CREATE_SUCCESS)
    public Long createUser(UserSaveReqVO createReqVO) {
        // 1.1 校验账户配合
        //  tenantService.handleTenantInfo(tenant -> {
//            long count = userMapper.selectCount();
//            if (count >= tenant.getAccountCount()) {
//                throw exception(USER_COUNT_MAX, tenant.getAccountCount());
//            }
        //  });
        if (createReqVO.getTenantId() == null) {
            createReqVO.setTenantId(TenantContextHolder.getTenantId());
        }
        // 1.2 校验正确性
        validateUserForCreateOrUpdate(null, createReqVO.getUsername(),
                createReqVO.getMobile(), createReqVO.getEmail(), createReqVO.getDeptId(), createReqVO.getPostIds());
        // 2.1 插入用户
        AdminUserDO user = BeanUtils.toBean(createReqVO, AdminUserDO.class);
        if (user.getTenantId() == null) {
            Set<Long> deptIds = createReqVO.getDeptIds();
            if (deptIds != null && !deptIds.isEmpty()) {
                Long[] objects = deptIds.toArray(new Long[0]);
                DeptDO deptDO = deptMapper.selectById(objects[0]);
                user.setTenantId(deptDO.getTenantId());
            } else {
                user.setTenantId(TenantContextHolder.getTenantId());
            }
        }
        user.setStatus(CommonStatusEnum.ENABLE.getStatus()); // 默认开启
        user.setPassword(encodePassword(createReqVO.getPassword())); // 加密密码
        userMapper.insert(user);

        // 2.2 插入关联岗位
        if (CollectionUtil.isNotEmpty(user.getPostIds())) {
            userPostMapper.insertBatch(convertList(user.getPostIds(),
                    postId -> new UserPostDO().setUserId(user.getId()).setPostId(postId)));
        }
        //插入关联部门
        if (CollectionUtil.isNotEmpty(createReqVO.getDeptIds())) {
            List<UserDeptDO> userDeptDOS = convertList(createReqVO.getDeptIds(),
                    deptId -> new UserDeptDO().setUserId(createReqVO.getId()).setDeptId(deptId)
                            .setTenantId(createReqVO.getTenantId()));
            userDeptMapper.insertBatch(userDeptDOS);
        }

        UserTenantDO userTenant = new UserTenantDO();
        userTenant.setUserId(user.getId()).setTenantId(user.getTenantId());
        userTenantMapper.insert(userTenant);

        // 3. 记录操作日志上下文
        LogRecordContext.putVariable("user", user);
        return user.getId();
    }

    @Override
    public Long assTenant(UserSaveReqVO createReqVO) {
        if (createReqVO.getId() == null) {
            throw exception(USER_ID_NULL);
        }
        if (createReqVO.getTenantId() == null) {
            createReqVO.setTenantId(TenantContextHolder.getTenantId());
        }
        UserTenantDO userTenantDO = userTenantMapper.selectOne("user_id", createReqVO.getId(), "tenant_id", createReqVO.getTenantId());
        if (userTenantDO == null) {
            UserTenantDO userTenant = new UserTenantDO();
            userTenant.setUserId(createReqVO.getId()).setStatus(0).setTenantId(createReqVO.getTenantId())
                    .setDeleted(Boolean.FALSE);
            userTenantMapper.insert(userTenant);
        } else {
            userPostMapper.deleteByUserIdAndTenantId(createReqVO.getId(), createReqVO.getTenantId());
            userDeptMapper.deleteByUserIdAndTenantId(createReqVO.getId(), createReqVO.getTenantId());
        }

        if (CollectionUtil.isNotEmpty(createReqVO.getPostIds())) {
            userPostMapper.insertBatch(convertList(createReqVO.getPostIds(),
                    postId -> new UserPostDO().setUserId(createReqVO.getId()).setPostId(postId)
                            .setTenantId(createReqVO.getTenantId())));
        }
        if (CollectionUtil.isNotEmpty(createReqVO.getDeptIds())) {
            List<UserDeptDO> userDeptDOS = convertList(createReqVO.getDeptIds(),
                    deptId -> new UserDeptDO().setUserId(createReqVO.getId()).setDeptId(deptId)
                            .setTenantId(createReqVO.getTenantId()));
            userDeptMapper.insertBatch(userDeptDOS);
        }
        return createReqVO.getId();
    }

    @Override
    public List userTree(Long scid) {


        return null;
    }

    @Override
    public Long registerUser(AuthRegisterReqVO registerReqVO) {
        // 1.1 校验账户配合
        tenantService.handleTenantInfo(tenant -> {
            long count = userMapper.selectCount();
            if (count >= tenant.getAccountCount()) {
                throw exception(USER_COUNT_MAX, tenant.getAccountCount());
            }
        });
        // 1.2 校验正确性
        validateUserForCreateOrUpdate(null, registerReqVO.getUsername(), null, null, null, null);

        // 2. 插入用户
        AdminUserDO user = BeanUtils.toBean(registerReqVO, AdminUserDO.class);
        user.setStatus(CommonStatusEnum.ENABLE.getStatus()); // 默认开启
        user.setPassword(encodePassword(registerReqVO.getPassword())); // 加密密码
        if (user.getTenantId() == null) {
            user.setTenantId(TenantContextHolder.getTenantId());
        }
        userMapper.insert(user);
        return user.getId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @LogRecord(type = SYSTEM_USER_TYPE, subType = SYSTEM_USER_UPDATE_SUB_TYPE, bizNo = "{{#updateReqVO.id}}",
            success = SYSTEM_USER_UPDATE_SUCCESS)
    public void updateUser(UserSaveReqVO updateReqVO) {
        updateReqVO.setPassword(null); // 特殊：此处不更新密码
        // 1. 校验正确性
        AdminUserDO oldUser = validateUserForCreateOrUpdate(updateReqVO.getId(), updateReqVO.getUsername(),
                updateReqVO.getMobile(), updateReqVO.getEmail(), updateReqVO.getDeptId(), updateReqVO.getPostIds());

        // 2.1 更新用户
        AdminUserDO updateObj = BeanUtils.toBean(updateReqVO, AdminUserDO.class);
        userMapper.updateById(updateObj);
        // 2.2 更新岗位
        updateUserPost(updateReqVO, updateObj);

        if (CollectionUtil.isNotEmpty(updateReqVO.getDeptIds())) {
            userDeptMapper.deleteByUserIdAndTenantId(updateReqVO.getId(), updateReqVO.getTenantId());
            List<UserDeptDO> userDeptDOS = convertList(updateReqVO.getDeptIds(),
                    deptId -> new UserDeptDO().setUserId(updateReqVO.getId()).setDeptId(deptId)
                            .setTenantId(updateReqVO.getTenantId()));
            userDeptMapper.insertBatch(userDeptDOS);
        }
        // 3. 记录操作日志上下文
        LogRecordContext.putVariable(DiffParseFunction.OLD_OBJECT, BeanUtils.toBean(oldUser, UserSaveReqVO.class));
        LogRecordContext.putVariable("user", oldUser);
    }

    private void updateUserPost(UserSaveReqVO reqVO, AdminUserDO updateObj) {
        Long userId = reqVO.getId();
        Set<Long> dbPostIds = convertSet(userPostMapper.selectListByUserId(userId), UserPostDO::getPostId);
        // 计算新增和删除的岗位编号
        Set<Long> postIds = CollUtil.emptyIfNull(updateObj.getPostIds());
        Collection<Long> createPostIds = CollUtil.subtract(postIds, dbPostIds);
        Collection<Long> deletePostIds = CollUtil.subtract(dbPostIds, postIds);
        // 执行新增和删除。对于已经授权的岗位，不用做任何处理
        if (!CollectionUtil.isEmpty(createPostIds)) {
            userPostMapper.insertBatch(convertList(createPostIds,
                    postId -> new UserPostDO().setUserId(userId).setPostId(postId)));
        }
        if (!CollectionUtil.isEmpty(deletePostIds)) {
            userPostMapper.deleteByUserIdAndPostId(userId, deletePostIds);
        }
    }

    @Override
    public void updateUserLogin(Long id, String loginIp) {
        userMapper.updateById(new AdminUserDO().setId(id).setLoginIp(loginIp).setLoginDate(LocalDateTime.now()));
    }

    @Override
    public void updateUserProfile(Long id, UserProfileUpdateReqVO reqVO) {
        // 校验正确性
        validateUserExists(id);
        validateEmailUnique(id, reqVO.getEmail());
        validateMobileUnique(id, reqVO.getMobile());
        // 执行更新
        userMapper.updateById(BeanUtils.toBean(reqVO, AdminUserDO.class).setId(id));
    }

    @Override
    public void updateUserPassword(Long id, UserProfileUpdatePasswordReqVO reqVO) {
        // 校验旧密码密码
        validateOldPassword(id, reqVO.getOldPassword());
        // 执行更新
        AdminUserDO updateObj = new AdminUserDO().setId(id);
        updateObj.setPassword(encodePassword(reqVO.getNewPassword())); // 加密密码
        userMapper.updateById(updateObj);
    }

    @Override
    public String updateUserAvatar(Long id, InputStream avatarFile) {
        validateUserExists(id);
        // 存储文件
        String avatar = fileApi.createFile(IoUtil.readBytes(avatarFile));
        // 更新路径
        AdminUserDO sysUserDO = new AdminUserDO();
        sysUserDO.setId(id);
        sysUserDO.setAvatar(avatar);
        userMapper.updateById(sysUserDO);
        return avatar;
    }

    @Override
    @LogRecord(type = SYSTEM_USER_TYPE, subType = SYSTEM_USER_UPDATE_PASSWORD_SUB_TYPE, bizNo = "{{#id}}",
            success = SYSTEM_USER_UPDATE_PASSWORD_SUCCESS)
    public void updateUserPassword(Long id, String password) {
        // 1. 校验用户存在
        AdminUserDO user = validateUserExists(id);

        // 2. 更新密码
        AdminUserDO updateObj = new AdminUserDO();
        updateObj.setId(id);
        updateObj.setPassword(encodePassword(password)); // 加密密码
        userMapper.updateById(updateObj);

        // 3. 记录操作日志上下文
        LogRecordContext.putVariable("user", user);
        LogRecordContext.putVariable("newPassword", updateObj.getPassword());
    }

    @Override
    public void updateUserStatus(Long id, Integer status) {
        // 校验用户存在
        validateUserExists(id);
        // 更新状态
        AdminUserDO updateObj = new AdminUserDO();
        updateObj.setId(id);
        updateObj.setStatus(status);
        userMapper.updateById(updateObj);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @LogRecord(type = SYSTEM_USER_TYPE, subType = SYSTEM_USER_DELETE_SUB_TYPE, bizNo = "{{#id}}",
            success = SYSTEM_USER_DELETE_SUCCESS)
    public void deleteUser(Long id) {
        // 1. 校验用户存在
        AdminUserDO user = validateUserExists(id);

        // 2.1 删除用户
        userMapper.deleteById(id);
        // 2.2 删除用户关联数据
        permissionService.processUserDeleted(id);
        // 2.2 删除用户岗位
        userPostMapper.deleteByUserId(id);

        // 3. 记录操作日志上下文
        LogRecordContext.putVariable("user", user);
    }

    @Override
    public AdminUserDO getUserByUsername(String username) {
        userMapper.selectByUsername(username);
        return userMapper.selectByUsername(username);
    }

    /**
     * 根据用户id获取用户信息
     *
     * @param userId
     * @return
     */
    @Override
    public AdminUserDO getUserById(Long userId) {
        return userMapper.selectById(userId);
    }

    @Override
    public AdminUserDO getUserByMobile(String mobile) {
        return userMapper.selectByMobile(mobile);
    }

    @Override
    public PageResult<UserRespVO> getUserPage(UserPageReqVO reqVO) {

        //默认使用则使用前端传递的租户信息
        //如果前端没有传递，则使用当前登录用户的租户信息
        Long tenantId = reqVO.getTenantId();
        if (reqVO.getTenantId() == null) {
            reqVO.setTenantId(TenantContextHolder.getTenantId());
            tenantId = TenantContextHolder.getTenantId();
        }
        PageResult<AdminUserDO> adminUserDOPageResult = getUserPage2(reqVO);
        List<AdminUserDO> list = adminUserDOPageResult.getList();

        List<UserRespVO> userRespVOS = UserConvert.INSTANCE.convertList(list);
        Map<Long, DeptDO> deptMap = new HashMap<>();
        for (UserRespVO au : userRespVOS) {
            Long userId = au.getId();
            //获取用户关联部门
            List<UserDeptDO> userDeptList = userDeptMapper.selectList(UserDeptDO::getUserId, userId, UserDeptDO::getTenantId, tenantId);
            List<Long> collect = userDeptList.stream().map(item -> item.getDeptId()).collect(Collectors.toList());
            au.setDeptIds(collect);
            for (UserDeptDO ud : userDeptList) {
                DeptDO deptDO = deptMap.get(ud.getDeptId());
                if (deptDO == null) {
                    deptDO = deptMapper.selectById(ud.getDeptId());
                    if (deptDO != null) {
                        deptMap.put(ud.getDeptId(), deptDO);
                    }
                }
                if (au.getDeptNames() == null) {
                    au.setDeptNames(new ArrayList<>());
                }
                if (deptDO != null) {
                    au.getDeptNames().add(deptDO.getName());
                }
            }

            List<UserPostDO> userPostDOS = userPostMapper.selectList(UserPostDO::getUserId, userId, UserPostDO::getTenantId, reqVO.getTenantId());
            for (UserPostDO up : userPostDOS) {
                if (au.getPostIds() == null) {
                    au.setPostIds(new HashSet<>());
                }
                au.getPostIds().add(up.getPostId());
            }
        }

        return new PageResult<>(userRespVOS,
                adminUserDOPageResult.getTotal());
    }

    @Override
    public PageResult<AdminUserDO> getUserPage2(UserPageReqVO reqVO) {
        Set<Long> userIds = reqVO.getRoleId() != null ?
                permissionService.getUserRoleIdListByRoleId(singleton(reqVO.getRoleId())) : new HashSet<>();
        List<UserDeptDO> userDeptDOS = new ArrayList<>();
        if (reqVO.getDeptId() != null) {
            Set<Long> deptSet = getDeptCondition(reqVO.getDeptId());
            userDeptDOS = userDeptMapper.selectListByDeptIds(deptSet);
            if (!userDeptDOS.isEmpty()) {
                Set<Long> collect = userDeptDOS.stream().map(user -> user.getUserId()).collect(Collectors.toSet());
                userIds.addAll(collect);
            }
        }
        if (userIds.isEmpty()) {
            if (reqVO.getTenantId() == null) {
                reqVO.setTenantId(TenantContextHolder.getTenantId());
            }
        } else {
            reqVO.setTenantId(null);
            reqVO.setDeptId(null);
        }
        //log.info("userIds::" + JSONObject.toJSONString(userIds));
        // 分页查询
        PageResult<AdminUserDO> adminUserDOPageResult = userMapper.selectPage(reqVO, userIds);
        return adminUserDOPageResult;
    }

    @Override
    public AdminUserDO getUser(Long id) {
        AdminUserDO adminUserDO = userMapper.selectById(id);

        return adminUserDO;
    }

    @Override
    public List<UserRespVO> getDeptUserList() {
        Long loginUserId = WebFrameworkUtils.getLoginUserId();
        List<UserRespVO> result = new ArrayList();
        List<UserDeptDO> userDeptDOS = userDeptMapper.selectList(UserDeptDO::getUserId, loginUserId);
        for (UserDeptDO ud : userDeptDOS) {
            List<AdminUserDO> adminUserDOS = userMapper.selectList(AdminUserDO::getDeptId, ud.getDeptId());
            List<UserRespVO> collect = adminUserDOS.stream().map(item -> {
                UserRespVO userRespVO = BeanUtils.toBean(item, UserRespVO.class);
                DeptDO deptDO = deptMapper.selectById(ud.getDeptId());
                userRespVO.setDeptName(deptDO.getName());
                return userRespVO;
            }).collect(Collectors.toList());
            result.addAll(collect);

            List<DeptDO> childDeptList = new ArrayList<>();
            deptService.getChildDeptByParentId(ud.getDeptId(), childDeptList);
            for (DeptDO dept : childDeptList) {
                adminUserDOS = userMapper.selectList(AdminUserDO::getDeptId, dept.getId());
                List<UserRespVO> childUser = adminUserDOS.stream().map(item -> {
                    UserRespVO userRespVO = BeanUtils.toBean(item, UserRespVO.class);
                    userRespVO.setDeptName(dept.getName());
                    return userRespVO;
                }).collect(Collectors.toList());
                result.addAll(childUser);
            }
        }

        List<DeptDO> deptDOS = deptMapper.selectList(DeptDO::getLeaderUserId, loginUserId);
        for (DeptDO ud : deptDOS) {
            List<AdminUserDO> adminUserDOS = userMapper.selectList(AdminUserDO::getDeptId, ud.getId());
            List<UserRespVO> collect = adminUserDOS.stream().map(item -> {
                UserRespVO userRespVO = BeanUtils.toBean(item, UserRespVO.class);
                userRespVO.setDeptName(ud.getName());
                return userRespVO;
            }).collect(Collectors.toList());
            result.addAll(collect);
        }
        return result;
    }

    @Override
    public List<DeptUserTree> getTenantUser() {
        Long tenantId = TenantContextHolder.getTenantId();
        List<DeptDO> deptDOS = deptMapper.selectList(DeptDO::getTenantId, tenantId);
//        Long root = 0L;
//        for(DeptDO dept:deptDOS){
//            if(dept.getParentId() == root.longValue()){
//                root = dept.getId();
//                break;
//            }
//        }
        return encapTree(deptDOS, 0L);
    }

    private List<DeptUserTree> encapTree(List<DeptDO> deptDOS, Long root) {
        List<DeptUserTree> result = new ArrayList();
        for (DeptDO dept : deptDOS) {
            if (dept.getParentId() == root.longValue()) {
                DeptUserTree du = new DeptUserTree();
                du.setId(dept.getId()).setLabel(dept.getName())
                        .setLeaf(Boolean.FALSE).setType("dept")
                        .setTenantId(TenantContextHolder.getTenantId())
                        .setParentId(dept.getParentId())
                        .setSort(dept.getSort());

                MPJLambdaWrapperX<AdminUserDO> queryWrapper = new MPJLambdaWrapperX<>();
                queryWrapper.eq(UserDeptDO::getDeptId, dept.getId());

                queryWrapper.innerJoin(UserDeptDO.class, UserDeptDO::getUserId, AdminUserDO::getId);
                List<AdminUserDO> adminUserDOS = userMapper.selectList(queryWrapper);
                List<DeptUserTree> children = adminUserDOS.stream().map(user -> {
                    DeptUserTree deptUser = new DeptUserTree();
                    deptUser.setId(user.getId()).setLabel(user.getNickname())
                            .setLeaf(Boolean.TRUE).setType("user")
                            .setTenantId(TenantContextHolder.getTenantId())
                            .setParentId(dept.getId())
                            .setSort(user.getSort());
                    return deptUser;
                }).collect(Collectors.toList());
                //获取子部门
                List<DeptUserTree> deptUserTrees = encapTree(deptDOS, dept.getId());
                //合并子部门和 本部门下的用户
                deptUserTrees.addAll(children);
                du.setChildren(deptUserTrees);
                result.add(du);
            }
        }
        return result;
    }


    @Override
    public UserRespVO getSystemUser(Long id) {
        AdminUserDO adminUserDO = userMapper.selectById(id);
        if (adminUserDO == null) {
            return null;
        }
        List<UserDeptDO> userDeptList = userDeptMapper.selectList(UserDeptDO::getUserId, adminUserDO.getId(),
                UserDeptDO::getTenantId, TenantContextHolder.getTenantId());
        UserRespVO userVO = BeanUtils.toBean(adminUserDO, UserRespVO.class);
        for (UserDeptDO ud : userDeptList) {
            DeptDO deptDO = deptMapper.selectById(ud.getDeptId());
            if (userVO.getDeptNames() == null) {
                userVO.setDeptNames(new ArrayList<>());
            }
            if (userVO.getDeptIds() == null) {
                userVO.setDeptIds(new ArrayList<>());
            }
            userVO.getDeptIds().add(ud.getDeptId());
            userVO.getDeptNames().add(deptDO.getName());
        }
        List<UserPostDO> userPostDOS = userPostMapper.selectList(UserPostDO::getUserId, id, UserPostDO::getTenantId, TenantContextHolder.getTenantId());
        for (UserPostDO up : userPostDOS) {
            if (userVO.getPostIds() == null) {
                userVO.setPostIds(new HashSet<>());
            }
            userVO.getPostIds().add(up.getPostId());
        }
        return userVO;
    }

    @Override
    public UserRespVO getSystemUser(UserSaveReqVO userRespVO) {
        AdminUserDO adminUserDO = userMapper.selectById(userRespVO.getId());
        if (adminUserDO == null) {
            return null;
        }
        if (userRespVO.getTenantId() == null) {
            userRespVO.setTenantId(TenantContextHolder.getTenantId());
        }
        List<UserDeptDO> userDeptList = userDeptMapper.selectList(UserDeptDO::getUserId, adminUserDO.getId(),
                UserDeptDO::getTenantId, userRespVO.getTenantId());
        UserRespVO userVO = BeanUtils.toBean(adminUserDO, UserRespVO.class);
        for (UserDeptDO ud : userDeptList) {
            DeptDO deptDO = deptMapper.selectById(ud.getDeptId());
            if (userVO.getDeptNames() == null) {
                userVO.setDeptNames(new ArrayList<>());
            }
            if (userVO.getDeptIds() == null) {
                userVO.setDeptIds(new ArrayList<>());
            }
            userVO.getDeptIds().add(ud.getDeptId());
            userVO.getDeptNames().add(deptDO.getName());
        }
        List<UserPostDO> userPostDOS = userPostMapper.selectList(UserPostDO::getUserId, userRespVO.getId(), UserPostDO::getTenantId, userRespVO.getTenantId());
        for (UserPostDO up : userPostDOS) {
            if (userVO.getPostIds() == null) {
                userVO.setPostIds(new HashSet<>());
            }
            userVO.getPostIds().add(up.getPostId());
        }
        return userVO;
    }

    @Override
    public List<AdminUserDO> getUserListByDeptIds(Collection<Long> deptIds) {
        if (CollUtil.isEmpty(deptIds)) {
            return Collections.emptyList();
        }
        return userMapper.selectListByDeptIds(deptIds);
    }

    @Override
    public List<AdminUserDO> getUserListByPostIds(Collection<Long> postIds) {
        if (CollUtil.isEmpty(postIds)) {
            return Collections.emptyList();
        }
        Set<Long> userIds = convertSet(userPostMapper.selectListByPostIds(postIds), UserPostDO::getUserId);
        if (CollUtil.isEmpty(userIds)) {
            return Collections.emptyList();
        }
        return userMapper.selectBatchIds(userIds);
    }

    @Override
    public List<AdminUserDO> getUserList(Collection<Long> ids) {
        if (CollUtil.isEmpty(ids)) {
            return Collections.emptyList();
        }
        return userMapper.selectBatchIds(ids);
    }

    @Override
    public void validateUserList(Collection<Long> ids) {
        if (CollUtil.isEmpty(ids)) {
            return;
        }
        // 获得岗位信息
        List<AdminUserDO> users = userMapper.selectBatchIds(ids);
        Map<Long, AdminUserDO> userMap = CollectionUtils.convertMap(users, AdminUserDO::getId);
        // 校验
        ids.forEach(id -> {
            AdminUserDO user = userMap.get(id);
            if (user == null) {
                throw exception(USER_NOT_EXISTS);
            }
            if (!CommonStatusEnum.ENABLE.getStatus().equals(user.getStatus())) {
                throw exception(USER_IS_DISABLE, user.getNickname());
            }
        });
    }

    @Override
    public List<AdminUserDO> getUserListByNickname(String nickname) {
        return userMapper.selectListByNickname(nickname);
    }

    @Override
    public List<UserRespVO> getUserListByName(String nickname) {
        MPJLambdaWrapperX<AdminUserDO> wrapper = new MPJLambdaWrapperX<>();
        wrapper.like(AdminUserDO::getNickname, nickname);

        List<AdminUserDO> adminUserDOS = userMapper.selectList(wrapper);
        List<UserRespVO> result = new ArrayList<>();
        for(AdminUserDO user:adminUserDOS){
            List<UserDeptDO> userDeptDOS = userDeptMapper.selectList(UserDeptDO::getUserId, user.getId());
            for(UserDeptDO ud:userDeptDOS){
                UserRespVO userRespVO = BeanUtils.toBean(user, UserRespVO.class);
                DeptDO deptDO = deptMapper.selectById(ud.getDeptId());
                if(deptDO != null) {
                    userRespVO.setDeptName(deptDO.getName());
                    userRespVO.setDeptId(deptDO.getId());
                }
                TenantDO tenantDO = tenantMapper.selectById(deptDO.getTenantId());
                if(tenantDO != null){
                    userRespVO.setTenantName(tenantDO.getName());
                }
                result.add(userRespVO);
            }

        }
//        List<UserRespVO> userList = adminUserDOS.stream().map(user -> {
//            UserRespVO userRespVO = BeanUtils.toBean(user, UserRespVO.class);
//            List<UserDeptDO> userDeptDOS = userDeptMapper.selectList(UserDeptDO::getUserId, user.getId());
//            List<Long> deptList = userDeptDOS.stream().map(ud -> ud.getDeptId()).collect(Collectors.toList());
//            List<DeptDO> deptDOS = deptMapper.selectList(DeptDO::getId, deptList);
//            List<DeptRespVO> deptRespList = deptDOS.stream().map(deptDO -> {
//                DeptRespVO deptRespVO = BeanUtils.toBean(deptDO, DeptRespVO.class);
//                TenantDO tenantDO = tenantMapper.selectById(deptDO.getTenantId());
//                if(tenantDO != null){
//                    deptRespVO.setTenantName(tenantDO.getName());
//                }
//                return deptRespVO;
//            }).collect(Collectors.toList());
//            userRespVO.setDeptList(deptRespList);
//            return userRespVO;
//        }).collect(Collectors.toList());
        return result;
    }

    /**
     * 获得部门条件：查询指定部门的子部门编号们，包括自身
     *
     * @param deptId 部门编号
     * @return 部门编号集合
     */
    private Set<Long> getDeptCondition(Long deptId) {
        if (deptId == null) {
            return Collections.emptySet();
        }
        Set<Long> deptIds = convertSet(deptService.getChildDeptList(deptId), DeptDO::getId);
        deptIds.add(deptId); // 包括自身
        return deptIds;
    }

    private AdminUserDO validateUserForCreateOrUpdate(Long id, String username, String mobile, String email,
                                                      Long deptId, Set<Long> postIds) {
        // 关闭数据权限，避免因为没有数据权限，查询不到数据，进而导致唯一校验不正确
        return DataPermissionUtils.executeIgnore(() -> {
            // 校验用户存在
            AdminUserDO user = validateUserExists(id);
            // 校验用户名唯一
            validateUsernameUnique(id, username);
            // 校验手机号唯一
            validateMobileUnique(id, mobile);
            // 校验邮箱唯一
            validateEmailUnique(id, email);
            // 校验部门处于开启状态
            deptService.validateDeptList(CollectionUtils.singleton(deptId));
            // 校验岗位处于开启状态
            postService.validatePostList(postIds);
            return user;
        });
    }

    @VisibleForTesting
    AdminUserDO validateUserExists(Long id) {
        if (id == null) {
            return null;
        }
        AdminUserDO user = userMapper.selectById(id);
        if (user == null) {
            throw exception(USER_NOT_EXISTS);
        }
        return user;
    }

    @VisibleForTesting
    void validateUsernameUnique(Long id, String username) {
        if (StrUtil.isBlank(username)) {
            return;
        }
        AdminUserDO user = userMapper.selectByUsername(username);
        if (user == null) {
            return;
        }
        // 如果 id 为空，说明不用比较是否为相同 id 的用户
        if (id == null) {
            throw exception(USER_USERNAME_EXISTS);
        }
        if (!user.getId().equals(id)) {
            throw exception(USER_USERNAME_EXISTS);
        }
    }

    @VisibleForTesting
    void validateEmailUnique(Long id, String email) {
        if (StrUtil.isBlank(email)) {
            return;
        }
        AdminUserDO user = userMapper.selectByEmail(email);
        if (user == null) {
            return;
        }
        // 如果 id 为空，说明不用比较是否为相同 id 的用户
        if (id == null) {
            throw exception(USER_EMAIL_EXISTS);
        }
        if (!user.getId().equals(id)) {
            throw exception(USER_EMAIL_EXISTS);
        }
    }

    @VisibleForTesting
    void validateMobileUnique(Long id, String mobile) {
        if (StrUtil.isBlank(mobile)) {
            return;
        }
        AdminUserDO user = userMapper.selectByMobile(mobile);
        if (user == null) {
            return;
        }
        // 如果 id 为空，说明不用比较是否为相同 id 的用户
        if (id == null) {
            throw exception(USER_MOBILE_EXISTS);
        }
        if (!user.getId().equals(id)) {
            throw exception(USER_MOBILE_EXISTS);
        }
    }

    /**
     * 校验旧密码
     *
     * @param id          用户 id
     * @param oldPassword 旧密码
     */
    @VisibleForTesting
    void validateOldPassword(Long id, String oldPassword) {
        AdminUserDO user = userMapper.selectById(id);
        if (user == null) {
            throw exception(USER_NOT_EXISTS);
        }
        if (!isPasswordMatch(oldPassword, user.getPassword())) {
            throw exception(USER_PASSWORD_FAILED);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class) // 添加事务，异常则回滚所有导入
    public UserImportRespVO importUserList(List<UserImportExcelVO> importUsers, boolean isUpdateSupport) {
        // 1.1 参数校验
        if (CollUtil.isEmpty(importUsers)) {
            throw exception(USER_IMPORT_LIST_IS_EMPTY);
        }
        // 1.2 初始化密码不能为空
        String initPassword = configApi.getConfigValueByKey(USER_INIT_PASSWORD_KEY);
        if (StrUtil.isEmpty(initPassword)) {
            throw exception(USER_IMPORT_INIT_PASSWORD);
        }

        // 2. 遍历，逐个创建 or 更新
        UserImportRespVO respVO = UserImportRespVO.builder().createUsernames(new ArrayList<>())
                .updateUsernames(new ArrayList<>()).failureUsernames(new LinkedHashMap<>()).build();
        importUsers.forEach(importUser -> {
            // 2.1.1 校验字段是否符合要求
            try {
                ValidationUtils.validate(BeanUtils.toBean(importUser, UserSaveReqVO.class).setPassword(initPassword));
            } catch (ConstraintViolationException ex) {
                respVO.getFailureUsernames().put(importUser.getUsername(), ex.getMessage());
                return;
            }
            // 2.1.2 校验，判断是否有不符合的原因
            try {
                validateUserForCreateOrUpdate(null, null, importUser.getMobile(), importUser.getEmail(),
                        importUser.getDeptId(), null);
            } catch (ServiceException ex) {
                respVO.getFailureUsernames().put(importUser.getUsername(), ex.getMessage());
                return;
            }

            // 2.2.1 判断如果不存在，在进行插入
            AdminUserDO existUser = userMapper.selectByUsername(importUser.getUsername());
            if (existUser == null) {
                userMapper.insert(BeanUtils.toBean(importUser, AdminUserDO.class)
                        .setPassword(encodePassword(initPassword)).setPostIds(new HashSet<>())); // 设置默认密码及空岗位编号数组
                respVO.getCreateUsernames().add(importUser.getUsername());
                return;
            }
            // 2.2.2 如果存在，判断是否允许更新
            if (!isUpdateSupport) {
                respVO.getFailureUsernames().put(importUser.getUsername(), USER_USERNAME_EXISTS.getMsg());
                return;
            }
            AdminUserDO updateUser = BeanUtils.toBean(importUser, AdminUserDO.class);
            updateUser.setId(existUser.getId());
            userMapper.updateById(updateUser);
            respVO.getUpdateUsernames().add(importUser.getUsername());
        });
        return respVO;
    }

    @Override
    public List<AdminUserDO> getUserListByStatus(Integer status) {
        return userMapper.selectListByStatus(status);
    }

    @Override
    public boolean isPasswordMatch(String rawPassword, String encodedPassword) {
        return passwordEncoder.matches(rawPassword, encodedPassword);
    }


    /**
     * 获得租户下所有用户
     *
     * @return 用户集合
     */
    @Override
    public List<AdminUserDO> getUserListByTenant() {
        Long tenantId = TenantContextHolder.getTenantId();

        LambdaQueryWrapper<AdminUserDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(AdminUserDO::getTenantId, tenantId);

        return userMapper.selectList(queryWrapper);
    }

    /**
     * 对密码进行加密
     *
     * @param password 密码
     * @return 加密后的密码
     */
    private String encodePassword(String password) {
        return passwordEncoder.encode(password);
    }

}
